// 现代 JavaScript Fetch API 使用和最佳实践
// 作者：AI助手
// 最后更新：2024年

/**
 * Fetch API 是现代 JavaScript 中处理网络请求的标准方式
 * 特点：
 * 1. 基于 Promise 的 API
 * 2. 支持请求和响应流
 * 3. 内置支持 CORS
 * 4. 支持请求取消
 */

// 1. 基本 Fetch 使用
// 1.1 GET 请求
async function fetchUserData(userId) {
    try {
        const response = await fetch(`https://api.example.com/users/${userId}`);
        
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('获取用户数据失败:', error);
        throw error;
    }
}

// 1.2 POST 请求
async function createUser(userData) {
    try {
        const response = await fetch('https://api.example.com/users', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer your-token'
            },
            body: JSON.stringify(userData)
        });

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        return await response.json();
    } catch (error) {
        console.error('创建用户失败:', error);
        throw error;
    }
}

// 2. 高级特性
// 2.1 请求取消
function fetchWithTimeout(url, options = {}, timeout = 5000) {
    const controller = new AbortController();
    const { signal } = controller;

    const timeoutId = setTimeout(() => controller.abort(), timeout);

    return fetch(url, {
        ...options,
        signal
    }).finally(() => clearTimeout(timeoutId));
}

// 2.2 请求重试
async function fetchWithRetry(url, options = {}, retries = 3) {
    try {
        return await fetch(url, options);
    } catch (error) {
        if (retries === 0) throw error;
        return fetchWithRetry(url, options, retries - 1);
    }
}

// 2.3 并发请求
async function fetchMultiple(urls) {
    try {
        const responses = await Promise.all(
            urls.map(url => fetch(url))
        );
        
        return await Promise.all(
            responses.map(response => response.json())
        );
    } catch (error) {
        console.error('并发请求失败:', error);
        throw error;
    }
}

// 3. 实际应用示例
// 3.1 API 客户端类
class ApiClient {
    constructor(baseUrl, options = {}) {
        this.baseUrl = baseUrl;
        this.options = {
            headers: {
                'Content-Type': 'application/json',
                ...options.headers
            }
        };
    }

    async request(endpoint, options = {}) {
        const url = `${this.baseUrl}${endpoint}`;
        const config = {
            ...this.options,
            ...options,
            headers: {
                ...this.options.headers,
                ...options.headers
            }
        };

        try {
            const response = await fetch(url, config);
            
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            return await response.json();
        } catch (error) {
            console.error(`API 请求失败: ${url}`, error);
            throw error;
        }
    }

    get(endpoint, options = {}) {
        return this.request(endpoint, { ...options, method: 'GET' });
    }

    post(endpoint, data, options = {}) {
        return this.request(endpoint, {
            ...options,
            method: 'POST',
            body: JSON.stringify(data)
        });
    }

    put(endpoint, data, options = {}) {
        return this.request(endpoint, {
            ...options,
            method: 'PUT',
            body: JSON.stringify(data)
        });
    }

    delete(endpoint, options = {}) {
        return this.request(endpoint, { ...options, method: 'DELETE' });
    }
}

// 3.2 使用示例
const api = new ApiClient('https://api.example.com', {
    headers: {
        'Authorization': 'Bearer your-token'
    }
});

// 获取用户列表
async function getUsers() {
    return api.get('/users');
}

// 创建新用户
async function createNewUser(userData) {
    return api.post('/users', userData);
}

// 4. 错误处理
// 4.1 自定义错误类
class ApiError extends Error {
    constructor(message, status, data) {
        super(message);
        this.name = 'ApiError';
        this.status = status;
        this.data = data;
    }
}

// 4.2 错误处理中间件
async function handleApiError(error) {
    if (error instanceof ApiError) {
        // 处理 API 错误
        console.error(`API 错误: ${error.status}`, error.data);
    } else if (error.name === 'AbortError') {
        // 处理请求取消
        console.error('请求被取消');
    } else {
        // 处理其他错误
        console.error('未知错误:', error);
    }
}

// 5. 最佳实践
// 5.1 请求拦截器
const requestInterceptors = [];
const responseInterceptors = [];

function addRequestInterceptor(interceptor) {
    requestInterceptors.push(interceptor);
}

function addResponseInterceptor(interceptor) {
    responseInterceptors.push(interceptor);
}

// 5.2 缓存策略
const cache = new Map();

async function fetchWithCache(url, options = {}) {
    const cacheKey = `${url}-${JSON.stringify(options)}`;
    
    if (cache.has(cacheKey)) {
        return cache.get(cacheKey);
    }

    const response = await fetch(url, options);
    const data = await response.json();
    
    cache.set(cacheKey, data);
    return data;
}

// 6. 使用示例
// 6.1 基本使用
async function demonstrateBasicUsage() {
    try {
        // 获取用户数据
        const user = await fetchUserData(1);
        console.log('用户数据:', user);

        // 创建新用户
        const newUser = await createUser({
            name: '张三',
            email: 'zhangsan@example.com'
        });
        console.log('新用户:', newUser);
    } catch (error) {
        await handleApiError(error);
    }
}

// 6.2 高级特性使用
async function demonstrateAdvancedFeatures() {
    try {
        // 带超时的请求
        const data = await fetchWithTimeout(
            'https://api.example.com/data',
            {},
            3000
        );
        console.log('带超时的数据:', data);

        // 并发请求
        const [users, posts] = await fetchMultiple([
            'https://api.example.com/users',
            'https://api.example.com/posts'
        ]);
        console.log('并发请求结果:', { users, posts });
    } catch (error) {
        await handleApiError(error);
    }
}

// 6.3 API 客户端使用
async function demonstrateApiClient() {
    try {
        // 获取用户列表
        const users = await getUsers();
        console.log('用户列表:', users);

        // 创建新用户
        const newUser = await createNewUser({
            name: '李四',
            email: 'lisi@example.com'
        });
        console.log('创建的用户:', newUser);
    } catch (error) {
        await handleApiError(error);
    }
}

// 运行示例
demonstrateBasicUsage();
demonstrateAdvancedFeatures();
demonstrateApiClient(); 